Intelligent Waiter

Zihan Luo & Yaoqing Yong

Introduction

The Intelligent Waiter is a robot car able to detect people in front of it, move forward to the person, and display an ordering system on the piTFT loaded on the car for ordering food. The robot car does this by utilizing a PIR sensor to detect human motion in front of it, an ultrasonic sensor to measure the distance between the car itself and the person or object in front, and two stepper servos are utilized to drive the car. The whole system is built on Raspberry Pi, which listens to the GPIO pins connected to the sensors, process sensor inputs, and display the ordering system onto the piTFT screen.

Objective

To create a user-friendly robot car providing ordering service without human help. We expect our robot car to detect upcoming customers, run to the customer, and provide menus for ordering and checkout. The Intelligent Waiter will be able to work in an unmanned restaurant.

Design

Hardware Design & Hardware Testing

The hardware we used were an ultrasonic sensor, a passive infrared (PIR) sensor, a buzzer, and two stepper motors.


The ultrasonic sensor was designed to keep measuring the distance between the front object and itself. In a while True loop, it would firstly emit ultrasound signal inaudible to humans, and then it would receive the echo signal back. The sound speed and the time elapsed during this process could be multiplied to calculate the distance from an object or a person in front of the sensor. Two GPIO pins (GPIO 18 and GPIO 24) on Raspberry Pi were used to connect its trigger and echo pins. And a threshold distance equals to 50 centimeters was set to configure the ultrasonic sensor so that it could judge whether the object was in such range using a built in function provided by gpiozero library. In the test case, we wrote the code controlling the ultrasonic sensor in an independent python file, and let the screen print the distance it measured every 0.2 second, as well as a message “In range” or “Out of range” depends on whether the distance was greater than the threshold distance (50 centimeters). By doing this, we verified that the circuit connection of the ultrasonic sensor was correct and it operated precisely following the code logic.


The passive infrared (PIR) sensor was designed to detect the human motion in front of it by continuously measuring the amount of infrared radiation it receives and producing a pulse when the received infrared radiation changes. There were three pins on the PIR sensor, which were Vcc, SNG, and GND, respectively connected to 5V pin, GPIO13, ground pin of the Raspberry Pi.

The test case was conducted in an independent python file too. Whenever the PIR sensor detect human movement in front, a message “ Detected people” would be print out on the command window.


A buzzer connected to GPIO 5 and 3.3V pin of the Raspberry Pi was designed to beep when our Intelligent robot detected an obstacle in front. It was active low, which means, GPIO 5 was supposed to be low level of voltage to make it beep. After beeping for a while (0.5 seconds in our code), GPIO 5 would be set to high level of voltage again. To test the buzzer, we added the beep function controlling its sound into the ultrasonic sensor module, so that every time the ultrasonic sensor detected an object in range would call this beep function to make the buzzer beep after printing “In range” onto the console.


Two stepper servos were respectively connected to GPIO 19 and GPIO 4 of the Raspberry Pi. One was left drive of the robot car, the other was right drive. In order to move forward, right servo needs to move clockwise, while left servo needs to move counter-clockwise. To achieve the control of the two servos, we firstly calibrated them to make them still when connected to 5V voltage. And then wrote clockwise() and counter_clockwise() function within which {46.7Hz frequency, 6.6% duty cycle} and {46.3Hz frequency, 7.4% duty cycle} were set separately. To stop both of them when obstacles encountered or customers got close enough, a function named stop_both() was implemented to set their duty cycle to 0 at the same time.

To test the operation of the two servos, calibration.py implemented in previous lab was used for calibration at first. After that, functions clockwise() and counter_clockwise() were added into the PIR sensor module, so that the two servos would be driven to move clockwise and counterclockwise after the PIR sensor detected customer movement in front and displayed “Detected people” onto the console. Function stop_both was added into the ultrasonic sensor module to stop servos when obstacles or customers were detected in range.



Software Design & Software Testing

We firstly implemented the subsystem for ordering by pygame. Customers could look through items’ picture on the PiTFT screen. Different kinds of food were categorized into four different genres. And genre list will be displayed on the first level of this system. After clicking on a particular genre name, a list of food pictures of this genre will be displayed. After clicking on any picture, a prompt message would be displayed, indicating the item had been successfully added into chart with its price. Continuous clicks would increase the number of this item added into the chart. “Checkout” button, “Back” button, and “Clear” button would be displayed on both levels. Upon clicking on “Checkout” button, a new level will display the total amount of the items in chart. To proceed the order, clicking on “OK’ button. The “Cancel” button on this level will go back to the previous level (list level or description level). To remove all items in the chart, simply clicking on the “Clear” button. Each level of interface was written as a function, within which a while loop controlled the Raspberry Pi to keep listening to the screen events and button events.

After completing the ordering part, all the sensor modules were integrated into the ordering system as conditions. More specifically, when PIR sensor detected a customer, the ordering system would then be displayed on the piTFT screen, and the servos would be drive to move forward. During the movement, the robot car would keep using the ultrasonic sensors to achieve automatic obstacle avoidance. Also, when the customer was close in its range, the robot car would stop in front the customer, waiting for ordering.

Software testing was implemented by black box testing techniques, operating on every level of the system and find any unexpected performance.

Testing

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Drawings


The sensors we use:

This is a picture


Our main menu:

This is a picture


Different categories of food selection:
(1) Burgers&Pizza

This is a picture


(2) Noodles&Rice

This is a picture


(3) Desserts

This is a picture


(4) Drinks

This is a picture


Checkout Interface

This is a picture

Results

Our Intelligent Waiter successfully achieved the following goals as designed:
It implements an ordering system on PiTFT, which allows the customer to order the food they want and checkout. Different categories of food, a main menu and a checkout interface are included. The customer can vary the quantity of each item and is allowed to get back to the main menu after each selection. A ‘clear’ button to delete all the items in the shopping cart is also implemented in case of incorrect ordering.
It integrates all hardware component (PIR sensor, ultrasound sensor, buzzer, servos) into a robot, which can detect human motion and avoid barriers within a certain distance;
The Waiter can automatically detect the customer, move forward and stop right in front of the customer, then displays the ordering menus for the customer to select.

Conclusion

Our final project was planned, developed and demonstrated as expected. We build a robot with hardware components: ultrasound sensor, infrared sensor, buzzer, servos plastic and wooden frames, Rapberry Pi and PiTFT, and software components: an ordering system implemented with Python. The robot can detect the customer and move towards he/she as well as avoid barriers. An ordering menu will be displayed on the PiTFT when the robot reaches the customer and the customer can select different categories of food and checkout.

Code Appendix

import pygame
from pygame.locals import *  # for event MOUSE variables
import pygame.display
import os
import time
import subprocess
import RPi.GPIO as GPIO
import math


def initial():
    display_buttons()
    pygame.display.flip()
    do_while_I(start_Time, True)


def display_buttons():
    screen.fill(BLACK)
    my_font = pygame.font.Font(None, 20)
    my_buttons = {'Burgers&Pizza': (150, 40), 'Noodles&Rice': (150, 80), 'Desserts': (150, 120), 'Drink': (150, 160)}
    for my_text, text_pos in my_buttons.items():
        text_surface = my_font.render(my_text, True, WHITE)
        rect = text_surface.get_rect(center=text_pos)
        screen.blit(text_surface, rect)


def display_buttons_II():
    my_font = pygame.font.Font(None, 20)
    my_buttons = {'Checkout': (75, 40), 'Back': (200, 40)}
    for my_text, text_pos in my_buttons.items():
        text_surface = my_font.render(my_text, True, WHITE)
        rect = text_surface.get_rect(center=text_pos)
        screen.blit(text_surface, rect)


def display_buttons_III():
    my_font = pygame.font.Font(None, 20)
    my_buttons = {'Back': (75, 40), 'Add into chart': (150, 40), 'Checkout': (200, 40)}
    for my_text, text_pos in my_buttons.items():
        text_surface = my_font.render(my_text, True, WHITE)
        rect = text_surface.get_rect(center=text_pos)
        screen.blit(text_surface, rect)


def do_while_I(start_Time, isRun):
    while (isRun):
        display_buttons()
        pygame.display.flip()
        for event in pygame.event.get():
            if (event.type is MOUSEBUTTONDOWN):
                pos = pygame.mouse.get_pos()
            elif (event.type is MOUSEBUTTONUP):
                pos = pygame.mouse.get_pos()
                x, y = pos
                pygame.font.init()
                myfont = pygame.font.SysFont(None, 30)
                if y < 60:
                    isRun = genre_1(start_Time, isRun)
                    print(isRun)
                elif y > 60 and y < 100:
                    isRun = genre_2(start_Time, isRun)
                elif y > 100 and y < 140:
                    isRun = genre_3(start_Time, isRun)
                elif y > 140 and y < 180:
                    isRun = genre_4(start_Time, isRun)
                # time.sleep(1)

        if (not GPIO.input(17)):
            isRun = False
        if (time.time() - start_Time > 30):
            isRun = False


def genre_1(start_Time, isRun):
    size = width, height = 320, 240
    black = 0, 0, 0
    screen = pygame.display.set_mode(size)
    rect1 = food1.get_rect()
    rect2 = food2.get_rect()
    rect3 = food3.get_rect()
    rect4 = food4.get_rect()
    rect5 = food5.get_rect()
    rect6 = food6.get_rect()
    rect1.centerx = 90
    rect1.centery = 100
    rect2.centerx = 180
    rect2.centery = 100
    rect3.centerx = 270
    rect3.centery = 100
    rect4.centerx = 90
    rect4.centery = 200
    rect5.centerx = 180
    rect5.centery = 200
    rect6.centerx = 270
    rect6.centery = 200

    isStart = isRun

    while isStart:
        screen.fill(black)
        screen.blit(food1, rect1)
        screen.blit(food2, rect2)
        screen.blit(food3, rect3)
        screen.blit(food4, rect4)
        screen.blit(food5, rect5)
        screen.blit(food6, rect6)
        display_buttons_II()
        pygame.display.flip()
        for event in pygame.event.get():
            if (event.type is MOUSEBUTTONDOWN):
                pos = pygame.mouse.get_pos()
            elif (event.type is MOUSEBUTTONUP):
                pos = pygame.mouse.get_pos()
                x, y = pos
                if y < 30:
                    if x < 160:
                        # isStart = False
                        res = checkout(isStart, isRun)
                        isStart = res[0]
                        isRun = res[1]
                        if not isStart:  # end genre interface, back to main menu
                            map.clear()
                            count.clear()
                    if x > 160 and x < 240:
                        isStart = False
                        return isRun
                if y > 40 and y < 110:
                    if x < 100:
                        text_added = my_font.render("added pizza($3.67) ", False, (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "pizza" in map:
                            count["pizza"] = count["pizza"] + 1
                        else:
                            map["pizza"] = "3.67"
                            count["pizza"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added a cheese burger($5.21) ", False, (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "cheese burger" in map:
                            count["cheese burger"] = count["cheese burger"] + 1
                        else:
                            map["cheese burger"] = "5.21"
                            count["cheese burger"] = 1
                    else:
                        text_added = my_font.render("added a bacon($4.8) ", False, (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "bacon" in map:
                            count["bacon"] = count["bacon"] + 1
                        else:
                            map["bacon"] = "4.8"
                            count["bacon"] = 1

                elif y > 110:
                    if x < 100:
                        text_added = my_font.render("added a hot dog(Italian)($4.1) ", False, (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "hot dog(Italian)" in map:
                            count["hot dog(Italian)"] = count["hot dog(Italian)"] + 1
                        else:
                            map["hot dog(Italian)"] = "4.1"
                            count["hot dog(Italian)"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added a hot dog(Rye)($4.1) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "hot dog(Rye)" in map:
                            count["hot dog(Rye)"] = count["hot dog(Rye)"] + 1
                        else:
                            map["hot dog(Rye)"] = "4.1"
                            count["hot dog(Rye)"] = 1
                    else:
                        text_added = my_font.render("added a sandwich($4.3) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "sandwich" in map:
                            count["sandwich"] = count["sandwich"] + 1
                        else:
                            map["sandwich"] = "4.3"
                            count["sandwich"] = 1

                print(map)
                print(count)
                print("")

        if (time.time() - start_Time > 30):
            isRun = False
    return isRun


def genre_2(start_Time, isRun):
    size = width, height = 320, 240
    black = 0, 0, 0
    screen = pygame.display.set_mode(size)
    rect1 = noodle1.get_rect()
    rect2 = noodle2.get_rect()
    rect3 = noodle3.get_rect()
    rect4 = noodle4.get_rect()
    rect5 = noodle5.get_rect()
    rect6 = noodle6.get_rect()
    rect1.centerx = 90
    rect1.centery = 100
    rect2.centerx = 180
    rect2.centery = 100
    rect3.centerx = 270
    rect3.centery = 100
    rect4.centerx = 90
    rect4.centery = 200
    rect5.centerx = 180
    rect5.centery = 200
    rect6.centerx = 270
    rect6.centery = 200

    isStart = isRun

    while isStart:
        screen.fill(black)
        screen.blit(noodle1, rect1)
        screen.blit(noodle2, rect2)
        screen.blit(noodle3, rect3)
        screen.blit(noodle4, rect4)
        screen.blit(noodle5, rect5)
        screen.blit(noodle6, rect6)
        display_buttons_II()
        pygame.display.flip()
        for event in pygame.event.get():
            if (event.type is MOUSEBUTTONDOWN):
                pos = pygame.mouse.get_pos()
            elif (event.type is MOUSEBUTTONUP):
                pos = pygame.mouse.get_pos()
                x, y = pos
                if y < 30:
                    if x < 160:
                        # isStart = False
                        res = checkout(isStart, isRun)
                        isStart = res[0]
                        isRun = res[1]
                        if not isStart:  # end genre interface, back to main menu
                            map.clear()
                            count.clear()
                    if x > 160 and x < 240:
                        isStart = False
                        return isRun
                if y > 40 and y < 110:
                    if x < 100:
                        text_added = my_font.render("added ramen($7.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "ramen" in map:
                            count["ramen"] = count["ramen"] + 1
                        else:
                            map["ramen"] = "7.5"
                            count["ramen"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added oishii ramen($8.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "oishii ramen" in map:
                            count["oishii ramen"] = count["oishii ramen"] + 1
                        else:
                            map["oishii ramen"] = "8.5"
                            count["oishii ramen"] = 1
                    else:
                        text_added = my_font.render("added seafood noodle($9.0) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "seafood noodle" in map:
                            count["seafood noodle"] = count["seafood noodle"] + 1
                        else:
                            map["seafood noodle"] = "9.0"
                            count["seafood noodle"] = 1

                elif y > 110:
                    if x < 100:
                        text_added = my_font.render("added udon($8.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "udon" in map:
                            count["udon"] = count["udon"] + 1
                        else:
                            map["udon"] = "8.5"
                            count["udon"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added tomato beef brisket($7.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "tomato beef brisket" in map:
                            count["tomato beef brisket"] = count["tomato beef brisket"] + 1
                        else:
                            map["tomato beef brisket"] = "7.5"
                            count["tomato beef brisket"] = 1
                    else:
                        text_added = my_font.render("added sunny egg($1.0) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "add sunny egg" in map:
                            count["add sunny egg"] = count["add sunny egg"] + 1
                        else:
                            map["add sunny egg"] = "1.0"
                            count["add sunny egg"] = 1

                print(map)
                print(count)
                print("")

        if (time.time() - start_Time > 30):
            isRun = False
    return isRun


def genre_3(start_Time, isRun):
    size = width, height = 320, 240
    black = 0, 0, 0
    screen = pygame.display.set_mode(size)
    rect1 = dessert1.get_rect()
    rect2 = dessert2.get_rect()
    rect3 = dessert3.get_rect()
    rect4 = dessert4.get_rect()
    rect5 = dessert5.get_rect()
    rect6 = dessert6.get_rect()
    rect1.centerx = 90
    rect1.centery = 100
    rect2.centerx = 180
    rect2.centery = 100
    rect3.centerx = 270
    rect3.centery = 100
    rect4.centerx = 90
    rect4.centery = 200
    rect5.centerx = 180
    rect5.centery = 200
    rect6.centerx = 270
    rect6.centery = 200

    isStart = isRun

    while isStart:
        screen.fill(black)
        screen.blit(dessert1, rect1)
        screen.blit(dessert2, rect2)
        screen.blit(dessert3, rect3)
        screen.blit(dessert4, rect4)
        screen.blit(dessert5, rect5)
        screen.blit(dessert6, rect6)
        display_buttons_II()
        pygame.display.flip()
        for event in pygame.event.get():
            if (event.type is MOUSEBUTTONDOWN):
                pos = pygame.mouse.get_pos()
            elif (event.type is MOUSEBUTTONUP):
                pos = pygame.mouse.get_pos()
                x, y = pos
                if y < 30:
                    if x < 160:
                        # isStart = False
                        res = checkout(isStart, isRun)
                        isStart = res[0]
                        isRun = res[1]
                        if not isStart:  # end genre interface, back to main menu
                            map.clear()
                            count.clear()
                    if x > 160 and x < 240:
                        isStart = False
                        return isRun
                if y > 40 and y < 110:
                    if x < 100:
                        text_added = my_font.render("added cherry cupcake($2.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "cherry cupcake" in map:
                            count["cherry cupcake"] = count["cherry cupcake"] + 1
                        else:
                            map["cherry cupcake"] = "2.5"
                            count["cherry cupcake"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added chocolate cake($3.0) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "chocolate cake" in map:
                            count["chocolate cake"] = count["chocolate cake"] + 1
                        else:
                            map["chocolate cake"] = "3.0"
                            count["chocolate cake"] = 1
                    else:
                        text_added = my_font.render("added pudding($2.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "pudding" in map:
                            count["pudding"] = count["pudding"] + 1
                        else:
                            map["pudding"] = "2.5"
                            count["pudding"] = 1

                elif y > 110:
                    if x < 100:
                        text_added = my_font.render("added muffin($2.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "muffin" in map:
                            count["muffin"] = count["muffin"] + 1
                        else:
                            map["muffin"] = "2.5"
                            count["muffin"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added cookie($1.8) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "cookie" in map:
                            count["cookie"] = count["cookie"] + 1
                        else:
                            map["cookie"] = "1.8"
                            count["cookie"] = 1
                    else:
                        text_added = my_font.render("added tiramisu($3.9) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "tiramisu" in map:
                            count["tiramisu"] = count["tiramisu"] + 1
                        else:
                            map["tiramisu"] = "3.9"
                            count["tiramisu"] = 1

                print(map)
                print(count)
                print("")

        if (time.time() - start_Time > 30):
            isRun = False
    return isRun


def genre_4(start_Time, isRun):
    size = width, height = 320, 240
    black = 0, 0, 0
    screen = pygame.display.set_mode(size)
    rect1 = drink1.get_rect()
    rect2 = drink2.get_rect()
    rect3 = drink3.get_rect()
    rect4 = drink4.get_rect()
    rect5 = drink5.get_rect()
    rect6 = drink6.get_rect()
    rect1.centerx = 90
    rect1.centery = 100
    rect2.centerx = 180
    rect2.centery = 100
    rect3.centerx = 270
    rect3.centery = 100
    rect4.centerx = 90
    rect4.centery = 200
    rect5.centerx = 180
    rect5.centery = 200
    rect6.centerx = 270
    rect6.centery = 200

    isStart = isRun

    while isStart:
        screen.fill(black)
        screen.blit(drink1, rect1)
        screen.blit(drink2, rect2)
        screen.blit(drink3, rect3)
        screen.blit(drink4, rect4)
        screen.blit(drink5, rect5)
        screen.blit(drink6, rect6)
        display_buttons_II()
        pygame.display.flip()
        for event in pygame.event.get():
            if (event.type is MOUSEBUTTONDOWN):
                pos = pygame.mouse.get_pos()
            elif (event.type is MOUSEBUTTONUP):
                pos = pygame.mouse.get_pos()
                x, y = pos
                if y < 30:
                    if x < 160:
                        # isStart = False
                        res = checkout(isStart, isRun)
                        isStart = res[0]
                        isRun = res[1]
                        if not isStart:  # end genre interface, back to main menu
                            map.clear()
                            count.clear()
                    if x > 160 and x < 240:
                        isStart = False
                        return isRun
                if y > 40 and y < 110:
                    if x < 100:
                        text_added = my_font.render("added black coffe($2.2) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "black coffe" in map:
                            count["black coffe"] = count["black coffe"] + 1
                        else:
                            map["black coffe"] = "2.2"
                            count["black coffe"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added taro milk($3.0) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "taro milk" in map:
                            count["taro milk"] = count["taro milk"] + 1
                        else:
                            map["taro milk"] = "3.0"
                            count["taro milk"] = 1
                    else:
                        text_added = my_font.render("added apple drink($4.5) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "apple drink" in map:
                            count["apple drink"] = count["apple drink"] + 1
                        else:
                            map["apple drink"] = "4.5"
                            count["apple drink"] = 1

                elif y > 110:
                    if x < 100:
                        text_added = my_font.render("added chocolate milkshake($5.0) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "chocolate milkshake" in map:
                            count["chocolate milkshake"] = count["chocolate milkshake"] + 1
                        else:
                            map["chocolate milkshake"] = "5.0"
                            count["chocolate milkshake"] = 1

                    elif x > 100 and x < 190:
                        text_added = my_font.render("added vanilla milkshake($5.0) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (x, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "vanilla milkshake" in map:
                            count["vanilla milkshake"] = count["vanilla milkshake"] + 1
                        else:
                            map["vanilla milkshake"] = "5.0"
                            count["vanilla milkshake"] = 1
                    else:
                        text_added = my_font.render("added soft drink($2.0) ", False,
                                                    (255, 0, 0))
                        screen.blit(text_added, (240, y))
                        pygame.display.flip()
                        time.sleep(0.4)
                        if "soft drink" in map:
                            count["soft drink"] = count["soft drink"] + 1
                        else:
                            map["soft drink"] = "2.0"
                            count["soft drink"] = 1

                print(map)
                print(count)
                print("")

        if (time.time() - start_Time > 30):
            isRun = False
    return isRun


def checkout(isStart, isRun):
    size = width, height = 320, 240
    screen = pygame.display.set_mode(size)
    screen.fill(BLACK)
    my_font = pygame.font.Font(None, 20)
    my_buttons = {'OK': (70, 20), 'Back': (200, 20)}
    for my_text, text_pos in my_buttons.items():
        text_surface = my_font.render(my_text, True, WHITE)
        rect = text_surface.get_rect(center=text_pos)
        screen.blit(text_surface, rect)
    text_surface_product = my_font.render('Product', True, WHITE)
    text_surface_price = my_font.render('Price', True, WHITE)
    text_surface_count = my_font.render('count', True, WHITE)
    screen.blit(text_surface_product, (50, 30))
    screen.blit(text_surface_price, (150, 30))
    screen.blit(text_surface_count, (250, 30))
    idx = 1
    total = 0
    for product in map:
        text_surface_product = my_font.render(product, True, WHITE)
        text_surface_price = my_font.render(map[product], True, WHITE)
        text_surface_count = my_font.render(str(count[product]), True, WHITE)
        total = total + float(map[product]) * count[product]
        screen.blit(text_surface_product, (50, 30 + 20 * idx))
        screen.blit(text_surface_price, (150, 30 + 20 * idx))
        screen.blit(text_surface_count, (250, 30 + 20 * idx))
        idx = idx + 1
    myfont = pygame.font.Font(None, 40)
    text_total = myfont.render("Total = " + str(round(total, 2)), False, WHITE)
    screen.blit(text_total, (125, 30 + 20 * (idx + 1)))
    pygame.display.flip()
    isStart_sub = isRun
    while isStart_sub:
        for event in pygame.event.get():
            if (event.type is MOUSEBUTTONDOWN):
                pos = pygame.mouse.get_pos()
            elif (event.type is MOUSEBUTTONUP):
                pos = pygame.mouse.get_pos()
                x, y = pos
                if y < 30:
                    if x < 100:
                        screen.fill(BLACK)
                        myfont = pygame.font.Font(None, 60)
                        text_surface = myfont.render("Thank you!", False, WHITE)
                        screen.blit(text_surface, (100, 100))
                        pygame.display.flip()
                        time.sleep(1)
                        isStart_sub = False
                        isStart = False

                    elif x > 120 and x < 240:
                        isStart_sub = False
                        isStart = True

    if (time.time() - start_Time > 30):
        isRun = False
    return isStart, isRun


def move_forward():
    control_servo(2, 1)#Right servo, clockwise
    control_servo(1, 2)#Left servo, counter_clockwise
    while True:
        if (distance() < 100) and (GPIO.input(GPIO_PIR)==False):
            stop_both()
            beep()
            GPIO.output(5, GPIO.HIGH)
            break
        elif(distance() < 10) and (GPIO.input(GPIO_PIR)==True):
            stop_both()
            initial()



def control_servo(servo_num,direction):
    if (servo_num == 1): #left servo
        if (direction ==1):
            clockwise(p1)
        elif (direction == 2):
            counter_clockwise(p1)
        else:
            stop(p1)

    elif (servo_num == 2): #right servo
        if (direction ==1):
            clockwise(p2)
        elif (direction == 2):
            counter_clockwise(p2)
        else:
            stop(p2)


def clockwise(p):
    p.ChangeFrequency(46.7)
    p.ChangeDutyCycle(6.6)
    p.start(6.6)

def counter_clockwise(p):
    p.ChangeFrequency(46.3)
    p.ChangeDutyCycle(7.4)
    p.start(7.4)

def stop_both():
    p1.ChangeDutyCycle(0)
    p1.start(0)
    p2.ChangeDutyCycle(0)
    p2.start(0)


def distance():
    # set Trigger to HIGH
    GPIO.output(GPIO_TRIGGER, True)

    # set Trigger after 0.01ms to LOW
    time.sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)

    StartTime = time.time()
    StopTime = time.time()

    # save StartTime
    while GPIO.input(GPIO_ECHO) == 0:
        StartTime = time.time()

    # save time of arrival
    while GPIO.input(GPIO_ECHO) == 1:
        StopTime = time.time()

    # time difference between start and arrival
    TimeElapsed = StopTime - StartTime
    # multiply with the sonic speed (34300 cm/s)
    # and divide by 2, because there and back
    distance = (TimeElapsed * 34300) / 2

    return distance


def beep():
    for i in range(1,6):
        GPIO.output(5, GPIO.LOW)
        time.sleep(0.5)
        GPIO.output(5,GPIO.HIGH)


start_Time = time.time()

GPIO.setmode(GPIO.BCM) # Set for broadcom numbering not board numbering
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
os.putenv('SDL_VIDEODRIVER', 'fbcon')   # Display on piTFT
os.putenv('SDL_FBDEV', '/dev/fb1')
os.putenv('SDL_MOUSEDRV', 'TSLIB')     # Track mouse clicks on piTFT
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')
pygame.init()
# pygame.mouse.set_visible(True)
# pygame.mouse.set_visible(False)
WHITE = 255, 255, 255
BLACK = 0, 0, 0
my_font = pygame.font.Font(None, 25)
screen = pygame.display.set_mode((320, 240))

food1 = pygame.image.load("1_1.png")
food2 = pygame.image.load("1_2.png")
food3 = pygame.image.load("1_3.png")
food4 = pygame.image.load("1_4.png")
food5 = pygame.image.load("1_5.png")
food6 = pygame.image.load("1_6.png")
noodle1 = pygame.image.load("2_1.png")
noodle2 = pygame.image.load("2_2.png")
noodle3 = pygame.image.load("2_3.png")
noodle4 = pygame.image.load("2_4.png")
noodle5 = pygame.image.load("2_5.png")
noodle6 = pygame.image.load("2_6.png")
dessert1 = pygame.image.load("3_1.png")
dessert2 = pygame.image.load("3_2.png")
dessert3 = pygame.image.load("3_3.png")
dessert4 = pygame.image.load("3_4.png")
dessert5 = pygame.image.load("3_5.png")
dessert6 = pygame.image.load("3_6.png")
drink1 = pygame.image.load("4_1.png")
drink2 = pygame.image.load("4_3.png")
drink3 = pygame.image.load("apple_drink.png")
drink4 = pygame.image.load("milkshake_chocolate.png")
drink5 = pygame.image.load("milkshake_vanilla.png")
drink6 = pygame.image.load("soft_drink.png")

# key:name, val:price
map = {}
count = {}

GPIO_PIR = 13
GPIO_TRIGGER = 18
GPIO_ECHO = 24
GPIO_BUZZER = 5
GPIO.setup(GPIO_PIR, GPIO.IN)
# set GPIO direction (IN / OUT)
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)
GPIO.setup(GPIO_BUZZER, GPIO.OUT)

try:
    while True:
        if (GPIO.input(GPIO_PIR) == True):
            print("somebody here")
            print("move forward (servo)")
            move_forward()
        else:
            print("Nobody")
        time.sleep(0.01)

except KeyboardInterrupt:
    print("Exit")
GPIO.cleanup()

Contact

          Zihan Luo (zl779@cornell.edu)                   Yaoqing Yong (yy875@cornell.edu)

W3C+Hates+Me Valid+CSS%21 Handcrafted with sweat and blood Runs on Any Browser Any OS